﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using HP.Cachalote.Repositories.Interfaces;
using HP.Cachalote.DataModels;
using System.Data.Entity;

namespace HP.Cachalote.Repositories.EntityFramework
{
    public class TodoItemRepository : RepositoryBase<TodoItem>, ITodoItemRepository
    {
        public TodoItemRepository(CachaloteContext dataContext) : base(dataContext) { }

        /// <summary>
        /// Add new entity.
        /// </summary>
        /// <param name="entity">The new entity will be added into database.</param>
        /// <returns>The id of the new added entity.</returns>
        public virtual object Add(TodoItem entity)
        {
            DataContext.TodoItems.Add(entity);
            return entity;
        }

        // <summary>
        /// Get entity by id.
        /// </summary>
        /// <param name="id">The specified id.</param>
        /// <returns>The matched data.</returns>
        public virtual TodoItem Get(object id)
        {
            return DataContext.TodoItems.Find(id);
        }

        /// <summary>
        /// Get entity by id. It will never return null. It will always return an entity or throw an exception.
        /// It is free to return a proxy instead. If you know that the value exist in the database, 
        /// and you don’t want to pay the extra select to have that, 
        /// but you want to get that value so we can add that reference to an object.
        /// </summary>
        /// <param name="id">The specified id.</param>
        /// <returns>The matched data.</returns>
        public virtual TodoItem Load(object id)
        {
            return Get(id);
        }

        /// <summary>
        /// Filter data by lambda expression.
        /// </summary>
        /// <param name="expression">The lambda expression that accepts T and return boolean.</param>
        /// <returns>An IQueryable list of data.</returns>
        public virtual IQueryable<TodoItem> Filter(Expression<Func<TodoItem, bool>> expression)
        {
            return DataContext.TodoItems.Where(expression).AsQueryable();
        }

        /// <summary>
        /// Get all data. You also can filter the data later since the returned result is a IQueryable collection.
        /// </summary>
        /// <returns>An IQueryable collection of data.</returns>
        public virtual IQueryable<TodoItem> GetAll()
        {
            return DataContext.TodoItems.AsQueryable();
        }

        /// <summary>
        /// Get the data's count by using provided lambda expression.
        /// </summary>
        /// <param name="expression">The lambda expression that accepts T and return boolean.</param>
        /// <returns>The data's count.</returns>
        public virtual int GetRowCount(Expression<Func<TodoItem, bool>> expression)
        {
            return DataContext.TodoItems.Where(expression).Count();
        }

        /// <summary>
        /// Update existing entity.
        /// </summary>
        /// <param name="entity">The entity will be updated.</param>
        public virtual void Update(TodoItem entity)
        {
            DataContext.TodoItems.Attach(entity);
        }

        /// <summary>
        /// Add or update entity.
        /// </summary>
        /// <param name="data">The entity will be updated if it is existing or added if it cannot be found.</param>
        public virtual void AddOrUpdate(TodoItem entity)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Delete the specified entity.
        /// </summary>
        /// <param name="entity">The entity will be deleted from database.</param>
        public virtual void Delete(TodoItem entity)
        {
            DataContext.TodoItems.Remove(entity);
        }

        // <summary>
        /// Get TodoItem by id. It will return null if the TodoItem does not exist.
        /// </summary>
        /// <param name="id">The specified id.</param>
        /// /// <param name="loadTodoLabel">True to load related TodoItem at the same time. False NOT load.</param>
        /// <returns>The matched TodoItem.</returns>
        public TodoItem Get(object id, bool loadTodoLabel)
        {
            if (loadTodoLabel)
            {
                //DataContext.LoadProperty(item, "Label");
                DataContext.TodoItems.Include(t => t.Label);
            }

            var item = Get(id);

            return item;
        }

        /// <summary>
        /// Filter TodoItem by lambda expression.
        /// </summary>
        /// <param name="expression">The lambda expression that accepts TodoItem and return boolean.</param>
        /// <param name="loadTodoLabel">True to load related TodoItem at the same time. False NOT load.</param>
        /// <returns>An IQueryable list of TodoItem.</returns>
        public IQueryable<TodoItem> Filter(Expression<Func<TodoItem, bool>> expression, bool loadTodoLabel)
        {
            if (loadTodoLabel)
            {
                //foreach (var item in items)
                //{
                //    DataContext.LoadProperty(item, "Label");
                //}

                DataContext.TodoItems.Include(item => item.Label);
            }

            return Filter(expression);
        }
    }
}
